%%%-------------------------------------------------------------------
%%% @author mirahs(2892727493@qq.com)
%%% @doc
%%%     环境变量管理器
%%% @end
%%%-------------------------------------------------------------------
-module(env_mgr).

-behaviour(gen_server).

-export([
    get/1
    ,get/2
    ,set/2
    ,save/2
    ,del/1
]).

-export([start_link/1]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-include("env.hrl").

-define(ets_name, ?MODULE).
-define(dets_file, "env.dets").


%%%===================================================================
%%% API functions
%%%===================================================================

-spec get(Key) -> Val | undefined when
    Key :: atom(),
    Val :: term().
get(Key) when erlang:is_atom(Key) ->
    case ets:lookup(?ets_name, Key) of
        [{Key, Val}] -> Val;
        _ -> undefined
    end.

-spec get(Key, Default) -> Val when
    Key :: atom(),
    Default :: term(),
    Val :: term().
get(Key, Default) when erlang:is_atom(Key) ->
    case ets:lookup(?ets_name, Key) of
        [{Key, Val}] -> Val;
        _ -> Default
    end.

-spec set(Key, Val) -> true when
    Key :: atom(),
    Val :: term().
set(Key, Val) when erlang:is_atom(Key) ->
    ets:insert(?ets_name, {Key, Val}).

-spec save(Key, Val) -> ok | {error, Reason} when
    Key :: atom(),
    Val :: term(),
    Reason :: term().
save(Key, Val) when erlang:is_atom(Key) ->
    set(Key, Val),
    dets:insert(?ets_name, {Key, Val}).

-spec del(Key) -> ok | {error, Reason} when
    Key :: atom(),
    Reason :: term().
del(Key) when erlang:is_atom(Key) ->
    ets:delete(?ets_name, Key),
    dets:delete(?ets_name, Key).


%%%===================================================================
%%% Spawning and gen_server implementation
%%%===================================================================

start_link(DirVar) ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [DirVar], []).


init([DirVar]) ->
    erlang:process_flag(trap_exit, true),

    ets:new(?ets_name, [named_table, public, set, {keypos, 1}, {read_concurrency, true}]),
    {ok, ?ets_name} = dets:open_file(?ets_name, [{file, DirVar ++ ?dets_file}, {keypos, 1}, {type, set}]),
    dets:to_ets(?ets_name, ?ets_name),

    set(?ENV_DIR_VAR, DirVar),

    {ok, undefined}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(_Request, State) ->
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    dets:close(?ets_name),
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.
